home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / program / tsfaqp35.zip / FAQPAS2.TXT < prev    next >
Internet Message Format  |  1996-11-08  |  47KB

  1. From ts@uwasa.fi Fri Nov 8 00:00:00 1996
  2. Subject: FAQPAS2.TXT contents
  3.  
  4.                              Copyright (c) 1993-1996 by Timo Salmi
  5.                                                All rights reserved
  6.  
  7. FAQPAS2.TXT More frequently (and not so frequently) asked Turbo
  8. Pascal questions with Timo's answers. The items are in no particular
  9. order.
  10.  
  11. You are free to quote brief passages from this file provided you
  12. clearly indicate the source with a proper acknowledgment.
  13.  
  14. Comments and corrections are solicited. But if you wish to have
  15. individual Turbo Pascal consultation, please post your questions to
  16. a suitable Usenet newsgroup like news:comp.lang.pascal.borland. It
  17. is much more efficient than asking me by email. I'd like to help,
  18. but I am very pressed for time. I prefer to pick the questions I
  19. answer from the Usenet news. Thus I can answer publicly at one go if
  20. I happen to have an answer. Besides, newsgroups have a number of
  21. readers who might know a better or an alternative answer. Don't be
  22. discouraged, though, if you get a reply like this from me. I am
  23. always glad to hear from fellow Turbo Pascal users.
  24.  
  25. ....................................................................
  26. Prof. Timo Salmi   Co-moderator of news:comp.archives.msdos.announce
  27. Moderating at ftp:// & http://garbo.uwasa.fi archives  193.166.120.5
  28. Department of Accounting and Business Finance  ; University of Vaasa
  29. ts@uwasa.fi http://uwasa.fi/~ts BBS 961-3170972; FIN-65101,  Finland
  30.  
  31. --------------------------------------------------------------------
  32. 26) How to get ansi control codes working in Turbo Pascal writes?
  33. 27) How to evaluate a function given as a string to the program?
  34. 28) How does one detect whether input (or output) is redirected?
  35. 29) How does one set the 43/50 line text mode?
  36. 30) How can I assign a value to an environment variable in TP?
  37. 31) How does one store, and then restore the original screen?
  38. 32) How can I convert a TPU unit of one TP version to another?
  39. 33) Which error is e.g. Runtime error 205, etc
  40. 34) Why can't I open read-only files? I get "File access denied".
  41. 35) How do I obtain high and low parts of a byte variable?
  42. 36) How can I set a hi-intensity color background in the text mode?
  43. 37) Where can I find a program to convert (Turbo) Pascal to C?
  44. 38) How can I read input without echoing to the screen?
  45. 39) How can I edit the readln input stream?
  46. 40) How can I write (brand) something into my executables?
  47. 41) What is wrong with my program? It hangs without a clear pattern?
  48. 42) How do I convert a decimal word into a hexadecimal string, etc?
  49. 43) How to determine the last drive?
  50. 44) How can I put a running clock into my Turbo Pascal program?
  51. 45) How to establish if a name refers to a directory or not?
  52. 46) How does one disable alt-ctrl-del?
  53. 47) How can I test whether a file exists?
  54. 48) What is the name of the current Turbo Pascal program?
  55. 49) How is the code for rebooting the PC written in Turbo Pascal?
  56. 50) How can I write inline code?
  57. --------------------------------------------------------------------
  58.  
  59. From ts@uwasa.fi Fri Nov 8 00:00:26 1996
  60. Subject: Using ansi codes in a TP program
  61.  
  62. 26. *****
  63.  Q: How to get ansi control codes working in Turbo Pascal writes?
  64.  
  65.  A: It is very simple, but one has to be aware of the pitfalls.
  66. Let's start from the assumption that ansi.sys or a corresponding
  67. driver has been loaded, and that you know ansi codes. If you don't,
  68. you'll find that information in the standard MS-DOS manual. To apply
  69. ansi codes you just include the ansi codes in your write statements.
  70. For example the following first clears the screen and then puts the
  71. text at location 10,10:
  72.    write (#27, '[2J');         (* the ascii code for ESC is 27 *)
  73.    write (#27, '[10;10HUsing ansi codes can be fun');
  74. If you want to test (as you should) whether ansi.sys or some some
  75. replacement driver has been loaded, you can use the ISANSIFN
  76. function from my ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip.
  77. Now the catches. If you have a
  78.    uses Crt;
  79. statement in your program, direct screen writes will be used, and
  80. the ansi codes won't work. You have either to leave out the Crt
  81. unit, or include
  82.    assign (output, '');
  83.    rewrite (output);
  84.    :
  85.    close (output);
  86. Occasionally I have seen it suggested that one should just set
  87.    DirectVideo := false;
  88. This is a popular misconception. It won't produce the desired
  89. result. I'm not claiming to know the reason for this quirk of Turbo
  90. Pascal. Rather it is an observation I've made.
  91.  
  92. -From: Bengt Oehman d92bo@efd.lth.se with a later dicussion with Bob
  93. Peck bpeck@prairienet.org and help from Duncan Murdoch
  94. dmurdoch@mast.queensu.ca. The `DirectVideo:=False' statement only
  95. tells the Crt unit to use BIOS calls instead of using direct
  96. video-memory writes. A demo program to illustrate the screen writing
  97. modes follows:
  98.  
  99. Program ScreenWriteDemo;
  100. USES Crt;
  101. BEGIN
  102.   Writeln('This is written directly to the video memory');
  103.   DirectVideo:=False;
  104.   Writeln('This is written via BIOS interrupt calls (int 10h)');
  105.   Assign(Output,'');
  106.   Append(Output);
  107.   Writeln('This is written via DOS calls (int 21h)');
  108. END.
  109.  
  110. A note: The latter could be also written as
  111.   Writeln(Output, 'This is written via DOS calls (int 21h)');
  112. since the writeln default is the standard output.
  113. --------------------------------------------------------------------
  114.  
  115. From ts@uwasa.fi Fri Nov 8 00:00:27 1996
  116. Subject: Writing an expression parser
  117.  
  118. 27. *****
  119.  Q: How to evaluate a function given as a string to the program?
  120.  
  121.  A: To do this you have to have a routine for parsing and evaluating
  122. your expression. This is a complicated task requiring a clever use
  123. of recursion. You can find such code in Stephen O'Brien (1988),
  124. Turbo Pascal, The Complete Reference. Borland-Osborne/McGraw-Hill,
  125. Chapter 10. Another, simpler piece of code can be found in Michael
  126. Yester (1989), Using Turbo Pascal, Que, Chapter 5.
  127.    I've also written such a function evaluation program myself, and
  128. much of it is based on the ideas in O'Brien with my own corrections
  129. and enhancements. The resulting program is available as fn.exe
  130. function evaluator in the ftp://garbo.uwasa.fi/pc/ts/tsfunc13.zip
  131. package (or whatever version number is the latest). Note however,
  132. that the source code is not included, nor available.
  133.    Tips from Justin Lee (ossm1jl@rex.uokhsc.edu):
  134.  67666 Sep 22 1994 ftp://garbo.uwasa.fi/pc/turboobj/parstp30.zip
  135.  parstp30.zip Recursive expression TP7.0/BP/VB/C++ parser, R.Loewy
  136. An excellent parser is included with all the Turbo Pascal versions
  137. since TP4.0 as part of the MCALC or TCALC spreadsheet example
  138. program. See mcparse.pas or tcparse.pas.
  139. --------------------------------------------------------------------
  140.  
  141. From ts@uwasa.fi Fri Nov 8 00:00:28 1996
  142. Subject: Detecting redirection
  143.  
  144. 28. *****
  145.  Q: How does one detect whether input (or output) is redirected?
  146.  
  147.  A: As we know input to a program can come from a file, from the
  148. console, or from a pipe or redirection. Examples of the latter are
  149.      type text.dat | program
  150.      program < text.dat
  151. A Turbo Pascal program can be made to detect the redirections using
  152. Interrupt 21Hex, function 44Hex, subfunction 00Hex. See PC Magazine
  153. April 16, 1991, p. 374 for the code, and Duncan (1988), Advanced
  154. MS-DOS Programming, pp. 412-413 for more information. Alternatively,
  155. you can utilize the preprogrammed routines
  156.   PIPEDIFN Is the standard input from redirection
  157.   PIPEDNFN Is the standard output redirected to nul
  158.   PIPEDOFN Is the standard output redirected
  159. from my ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip units.
  160. --------------------------------------------------------------------
  161.  
  162. From ts@uwasa.fi Fri Nov 8 00:00:29 1996
  163. Subject: Setting the 43/50 line text mode
  164.  
  165. 29. *****
  166.  Q: How does one set the 43/50 line text mode?
  167.  
  168.  A: Quite simple. Just apply TextMode (C80 + font8x8).  Requires a
  169. "uses Crt;". First, however, you should test that you have a at
  170. least an EGA video adapter. (See DetectGraph in your TP manual).
  171. Also see TSUTLE.NWS in ftp://garbo.uwasa.fi/pc/ts/tsutle22.zip (or
  172. whichever version number is the current) for the non-standard wide
  173. text modes like 132x43.
  174.   { An example }
  175.   uses Crt;
  176.   var InitialMode : integer;
  177.   begin
  178.     InitialMode := LastMode;
  179.     TextMode (CO80 + Font8x8);
  180.     TextColor (LightCyan);
  181.     writeln ('Test1');
  182.     readln;
  183.     {}
  184.     TextMode (CO40);
  185.     writeln ('Test2');
  186.     readln;
  187.     {}
  188.     TextMode (InitialMode);
  189.     TextColor (Yellow);
  190.     writeln ('Test3');
  191.     readln;
  192.   end.
  193. --------------------------------------------------------------------
  194.  
  195. From ts@uwasa.fi Fri Nov 8 00:00:30 1996
  196. Subject: Assigning environment variable values
  197.  
  198. 30. *****
  199.  Q: How can I assign a value to an environment variable in TP?
  200.  
  201.  A: For assigning a value to (a parent process's) environment value
  202. you have to access and manipulate the Program Segment Prefix and
  203. Memory Control Blocks. This is a rather complicated undertaking. A
  204. source code with an accompanying article by Trudy Neuhaus can be
  205. found in PC Magazine Volume 11 Number 1 pages 425-427.
  206.    The budding TP programmers should note that the elementary trick
  207. of Exec (GetEnv('comspec'), '/c set key=whatever') will achieve only
  208. a transient result for the duration of the exec shell. When you exit
  209. the shell after this endeavor, the environment will be as it was.
  210.    Here is about the why. When the above command is executed, MS-DOS
  211. makes a copy of the environment, and uses the copy. When the above
  212. shelling terminates, the copy of the environment is deleted, and the
  213. original is restored. Hence the above trick cannot be used to change
  214. the parent environment.
  215.    If you don't want to try to go through this rather complicated
  216. task yourself, the routines
  217.  "SETEVN   Set a parent environment variable (variable=value)"
  218.  "SETENVSH Set an environment variable for the duration of shelling"
  219. can be found in my TP TPU collection ftp://garbo.uwasa.fi/pc/ts/
  220. tspa35*.zip (* = 40,50,55,60,70). No source code is included, nor
  221. available for tspa35. However, there is a TPENV section within
  222. ftp://garbo.uwasa.fi/pc/turbopas/bonus507.zip. From zeta@tcscs.com
  223. Gregory Youngblood: For a source code see /pc/source/setenv.zoo at
  224. Garbo.
  225.    One further detail. Users sometimes ask how one can change the
  226. prompt or the path from within a Turbo Pascal program. This is in no
  227. way different from changing the value of any other environment
  228. variable. Both PATH and PROMPT are environment variables that can be
  229. set with the MS-DOS SET command in the fashion described in the
  230. above. This is not changed in any way by the fact that you can apply
  231. PROMPT and PATH also in an alternative format not requiring the SET
  232. command.
  233. --------------------------------------------------------------------
  234.  
  235. From ts@uwasa.fi Fri Nov 8 00:00:31 1996
  236. Subject: Saving the screen
  237.  
  238. 31. *****
  239.  Q: How does one store, and then restore the original screen?
  240.  
  241.  A: Here is a simple outline for storing and restoring a text mode
  242. screen in the standard 80 x 25 mode. Note that the code below is
  243. incomplete in a sense that it works for a color monitor only,
  244. because the monochrome screen address is $B000:$0000.
  245.    For storing and restoring the graphics screen see Ohlsen & Stoker
  246. (1989), Turbo Pascal Advanced Techniques, Que, pp 333-337.
  247.   uses Crt;
  248.   type ScreenType = array [1..4000] of byte;        (* 2 x 80 x 25 *)
  249.   var ColorScreen : ScreenType Absolute $B800:$0000;
  250.       SavedScreen : ScreenType;
  251.       posx, posy : byte;
  252.   begin
  253.     SavedScreen := ColorScreen;      (* Save the screen *)
  254.     posx := WhereX; posy := WhereY;  (* Save the cursor position *)
  255.     writeln ('A simple demo storing and restoring the color text screen');
  256.     writeln ('By Prof. Timo Salmi, ts@uwasa.fi');
  257.     writeln; write ('Press <-'''); readln;
  258.     ColorScreen := SavedScreen;   (* Restore the screen *)
  259.     GotoXY(posx,posy);            (* Go to the stored cursor position *)
  260.   end.
  261. If you would prefer not using the Crt unit, you can apply WHEREXFN,
  262. WHEREYFN, and GOATXY from TSUNTG.TPU from my units collection
  263. ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip.
  264.    If you wish to test for the monitor type, that is choose between
  265. $B800:$0000 and $B000:$0000 bases, you can use the following
  266. function to test for the monochrome adapter.
  267.   function MONOFN : boolean;
  268.   var regs : registers;
  269.   begin
  270.     FillChar (regs, SizeOf(regs), 0);
  271.     regs.ah := $0F;
  272.     Intr ($10, regs);
  273.     monofn := (regs.al = 7);
  274.   end;  (* monofn *)
  275. --------------------------------------------------------------------
  276.  
  277. From ts@uwasa.fi Fri Nov 8 00:00:32 1996
  278. Subject: Converting TPUs
  279.  
  280. 32. *****
  281.  Q: How can I convert a TPU unit of one TP version to another?
  282.  
  283.  A: Forget it. In practical terms such a conversion is not on. The
  284. Turbo Pascal TPU units are strictly version dependent. If there were
  285. a working solution I assume we would have heard of it long since.
  286. The hacks that have been tried won't solve this dilemma. For all
  287. practical purposes you need the source code and the relevant
  288. compiler version.
  289.    You may nevertheless wish to ascertain for which version a TPU
  290. unit has been compiled. This is very simple. Just look at the first
  291. four character of a TPU file. The codes are
  292.  TPU0  for 4.0
  293.  TPU5  for 5.0
  294.  TPU6  for 5.5
  295.  TPU9  for 6.0
  296.  TPUQ  for 7.0 real mode
  297. But don't go editing these. It will not get you anywhere.
  298.    Granted, there has been much discussion in the Usenet newsgroup
  299. news:comp.lang.pascal.borland about the theoretical possibility of a
  300. converter. However, unless someone really comes forward with a
  301. working, publicly distributable solution, the discussion remains
  302. academic. The practical answer is that there is no way doing the
  303. conversion without the source code.
  304. --------------------------------------------------------------------
  305.  
  306. From ts@uwasa.fi Fri Nov 8 00:00:33 1996
  307. Subject: Finding about runtime errors
  308.  
  309. 33. *****
  310.  Q: Which error is e.g. Runtime error 205
  311.  
  312.  A: Basically this is a case of RTFM (read the f*ing manual). But it
  313. is very easy to find out even without resorting to the manual. Put
  314. temporarily the statement RunError (205); as the first statement of
  315. your program. Then run your program from the Turbo Pascal IDE, that
  316. is from within the TP editor. The description of the error will
  317. appear.
  318.    If you run a program from within a Turbo Pascal IDE, it is
  319. advisable to turn on the debug options on. You'll get both the error
  320. number and the description. Furthermore by pressing F1 after the
  321. error you get its description in a more verbal format.
  322.    One further trick is to put "uses TSERR"; (Include verbal
  323. run-time error messages) into your program. If you do that, the
  324. run-time errors will be given with a verbal description not just as
  325. a number. TSERR.TPU is part of my TPU collection at Garbo
  326. ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip.
  327.    In TP 7.0 the run time errors can also be found by invoking
  328. "Help" from the main manu (Alt-H) and selecting "Error messages".
  329. --------------------------------------------------------------------
  330.  
  331. From ts@uwasa.fi Fri Nov 8 00:00:34 1996
  332. Subject: Opening read-only files
  333.  
  334. 34. *****
  335.  Q: Why can't I open read-only files? I get "File access denied".
  336.  
  337.  A: The answer is rather simple, but it is not well displayed in the
  338. manuals. In order to read a read-only file you have to set the
  339. FileMode as 0 like below. Else you'll get runtime error 005 "File
  340. access denied".
  341.   var f      : text;          (* Can be any file type *)
  342.       savefm : byte;
  343.   begin
  344.     savefm := FileMode;       (* Save the current FileMode status *)
  345.     FileMode := 0;            (* The default is 2 *)
  346.     assign (f, 'readonly.txt');
  347.     reset (f);
  348.     { have your wicked ways }
  349.     close (f);
  350.     FileMode := savefm;       (* Restore the original FileMode *)
  351.   end.
  352. --------------------------------------------------------------------
  353.  
  354. From ts@uwasa.fi Fri Nov 8 00:00:35 1996
  355. Subject: Getting a nybble from a byte
  356.  
  357. 35. *****
  358.  Q: I have a variable of type BYTE and would like to extract two
  359. numbers from it. (The first 4 bits making up number A, the second 4
  360. bits making up number B).  How can I extract these two numbers?
  361.  
  362.  A: Ah, this question brings back the good bad old days of the
  363. Commodore C64 programming when bit operations were rather a rule
  364. than an exception. Here is the solution.
  365.   function HIBYTEFN (x : byte) : byte;
  366.   begin
  367.     hibytefn := x Shr 4;           (* Shift right by four bits *)
  368.   end;
  369.   {}
  370.   function LOBYTEFN (x : byte) : byte;
  371.   begin
  372.     lobytefn := x and 15;          (* x and 00001111 *)
  373.   end;
  374. From Patrick Taylor (exuptr@exu.ericsson.se): Ah, leave it to Timo
  375. to come up with a different way! An other is (n div 16)
  376. (n mod 16).
  377.    Patrick is right.  But unless the compiler is optimized, the
  378. former produces more efficient code. Not that it really makes any
  379. practical difference whatsoever.
  380.    Of course the fastest code is produced using assembler as pointed
  381. out by Maarten Pennings (maarten@cs.ruu.nl) who provided the
  382. following inline example:
  383.   function high(b:byte):byte;
  384.     inline($58         { POP AX      | AH=?, AL=b       }
  385.           /$30/$e4     { XOR AH,AH   | AH=0, AL=b       }
  386.           /$b9/$04/$00 { MOV CX,0004 | AH=0, AL=b, CL=4 }
  387.           /$d3/$e8     { SHR AX,CL   | AX=b shr 4       }
  388.           );
  389.  
  390.  A2: Getting a word from a longint can alternatively be achieved
  391. without any calculations by using a kind of typecasting. Below is
  392. the code I have utilized in ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip.
  393.   (* Get the high-order word of the longint argument *)
  394.   function HIWORDFN (x : longint) : word;
  395.   type type1 = record
  396.                  low  : word;
  397.                  high : word;
  398.                end;
  399.   var m1 : type1 absolute x;
  400.   begin
  401.     hiwordfn := m1.high;
  402.   end;  (* hiwordfn *)
  403. --------------------------------------------------------------------
  404.  
  405. From ts@uwasa.fi Fri Nov 8 00:00:36 1996
  406. Subject: Setting hi-intensity background
  407.  
  408. 36. *****
  409.  Q: How can I set a hi-intensity color background in the text mode?
  410.  
  411.  A: As you should know, the you can test for a blinking text for
  412. example as follows.
  413.   uses Crt;
  414.   begin
  415.     TextColor (11 + 128);  (* or LightCyan + Blink *)
  416.     TextBackground (Blue);
  417.     writeln ('What''s the catch?');  (* An aside, note the '' pair *)
  418.   end.
  419. In the above, bit 7 (the 128) controls the blinking. If you have at
  420. least an EGA, you can alter the interpretation of the highest text
  421. color bit to denote a hi-intensity background, but then you lose the
  422. the blinking. The following piece of code disables blinking,
  423. enabling a hi-intensity background.
  424.   uses Dos;
  425.   var regs : registers;
  426.   begin
  427.     FillChar (regs, SizeOf(regs), 0); (* An initialization precaution *)
  428.     regs.ah := $10;                   (* Function $10 *)
  429.     regs.al := $03;                   (* Subfunction $03 *)
  430.     regs.bl := $00;
  431.     Intr ($10, regs);      (* ROM BIOS video driver interrupt *)
  432.   end.
  433. To enable blinking again, set regs.bl := $01; Any high-intensity
  434. background you may have currently on the screen, will instantly
  435. change into a blinking text a a low-intensity background.
  436.  
  437.  A2: The previous answer assumes at least an EGA. Otherwise ports
  438. must be accessed. This is both advanced and dangerous programming,
  439. because errors in handling posts can do real harm. Besides it is
  440. fair to require at least an EGA in writing modern programs, at least
  441. for non-laptops, and on the latter the colors don't really matter
  442. for CGA and below. Let's take a look, nevertheless, how this is done
  443. for a CGA. Note that this won't work an an EGA and beyond, not at
  444. least in my tests. For detecting the video adapter you have, see the
  445. DetectGraph procedure in you Turbo Pascal manual.
  446.    First we need some basics from MEMORY.LST in Ralf Brown's
  447. ftp://garbo.uwasa.fi/pc/programming/inter52b.zip (or whatever
  448. version is current):
  449.  Format of BIOS Data Segment at segment 40h:
  450.   63h WORD Video CRT controller base address: color=03D4h, mono=03B4h
  451.   65h BYTE Video current setting of mode select register 03D8h/03B8h
  452. From David Jurgens's ftp://garbo.uwasa.fi/pc/programming/helppc21.zip
  453. we see
  454.   3D0-3DF Color Graphics Monitor Adapter (ports 3D0-3DB are
  455.           write only, see 6845)
  456.   3D8 6845 Mode control register (CGA, EGA, VGA, except PCjr)
  457. From Darryl Friesen's (friesend@jester.usask.ca) in the late
  458. comp.lang.pascal we have, the following procedure, with my own added
  459. comments (* *).
  460.   procedure SetBlinkState (state : boolean);
  461.   var ModeRegPort : word;
  462.       ModeReg     : byte;
  463.   begin
  464.     Inline($FA); { CLI }           (* Interrupts off *)
  465.     ModeRegPort := MemW[$0040:$0063]+4;  (* Typically $03D4+4 = $03D8 *)
  466.     ModeReg := Mem[$0040:$0065];   (* Typically 1001 *)
  467.     if state then                  (* Bit 5 controls blink enable *)
  468.       ModeReg := ModeReg or $20    (* $20 = 00100000 (base2) *)
  469.     else
  470.       ModeReg := ModeReg and $DF;  (* $DF = 11011111 disable *)
  471.     Port[ModeRegPort] := ModeReg;  (* Typically $9 = 00001001 *)
  472.     Mem[$0040:$0065] := ModeReg;   (*       or $29 = 00101001 *)
  473.     Inline($FB) { STI }            (* Interrupts on *)
  474.   end;
  475. --------------------------------------------------------------------
  476.  
  477. From ts@uwasa.fi Fri Nov 8 00:00:37 1996
  478. Subject: Pascal to C
  479.  
  480. 37. *****
  481.  Q: Where can I find a program to convert (Turbo) Pascal to C?
  482.  
  483.  A: This is a relevant question, but I have placed elsewhere the
  484. tips on the "looking for a program" questions. Here are the
  485. pointers to further pointers :-). (The FAQ versions might have been
  486. updated since I wrote this.)
  487.  ftp://garbo.uwasa.fi/pc/pd2/camfaq.zip
  488.  comp.archives.msdos.(d/announce) FAQ (general finding)
  489.  :
  490.  ftp://garbo.uwasa.fi/pc/ts/tsfaqn45.zip
  491.  Questions from UseNet and Timo's answers
  492.  :
  493.  ftp://garbo.uwasa.fi/pc/pd2/faquote.zip
  494.  Old information from tsfaq Frequently Asked Questions
  495. --------------------------------------------------------------------
  496.  
  497. From ts@uwasa.fi Fri Nov 8 00:00:38 1996
  498. Subject: Turning off the input echo
  499.  
  500. 38. *****
  501.  Q: How can I read input without echoing to the screen?
  502.  
  503.  A: It is fairly simple. Study this example source code, with the
  504. manual, if need be.
  505.   uses Crt;
  506.   var password : string;
  507.   {}
  508.   (* Read without echoing *)
  509.   procedure GETPASS (var s : string);
  510.   var ch : char;
  511.   begin
  512.     s := '';
  513.     repeat
  514.       ch := ReadKey;
  515.       case ch of
  516.          #0 : ch := ReadKey;  (* Discard two-character keys, like F1 *)
  517.         #13 : exit;           (* Enter has been pressed *)
  518.         #1..#12,#14..#31,#255 :;  (* Discard the special characters *)
  519.         else s := s + ch;
  520.       end;
  521.    until false;
  522.   end;  (* getpass *)
  523.   {}
  524.   (* The main program *)
  525.   begin
  526.     write ('Password: ');
  527.     GETPASS (password);
  528.     writeln;
  529.     writeln (password);
  530.   end.
  531.   {}
  532. If you wish to be able to edit the input stream, like having the
  533. BackSpace functional, that is more complicated, and is left as an
  534. exercise after these basics. A hint: 8 : Delete (s, Length(s), 1);
  535.    If you wish to display e.g. a star '*' for each character
  536. entered, as is sometimes done in getting passwords, add a
  537. appropriate write('*') to the else option in the case statement
  538. somewhat like this: else begin s := s + ch; write ('*'); end;
  539.    There is another approach to this problem pointed out by Colin
  540. Lamond colin@sound.demon.co.uk. Quite innovative in its simplicity
  541. once one comes to think of it. "Set the textcolor, and the
  542. textbackground to the same color, and so the typed text can not be
  543. seen on the screen."
  544. --------------------------------------------------------------------
  545.  
  546. From ts@uwasa.fi Fri Nov 8 00:00:39 1996
  547. Subject: Input line-editing
  548.  
  549. 39. *****
  550.  Q: How can I edit the readln input stream?
  551.  
  552.  A: In practice, if you wish to use anything beyond simple the
  553. BackSpace deleting, you'll have to build your own line editing
  554. routines expanding on the code in the previous item. It is quite a
  555. task, and you can alternatively find the preprogrammed routines in
  556. my Turbo Pascal units ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip (or
  557. whatever version number is current).
  558.  EDRDEBLN Editable Readln with ctrl-c, break trapping, pre-fill etc
  559.  EDRDEFLN Editable Readln with recall, pre-fill, and insert toggle
  560.  EDRDLN   Readln with line-editing potential (the simplest)
  561.  EDREABLN Edreadln with ctrl-c and break trapping
  562.  EDREADLN Editable Readln with recall, and insert toggle
  563. --------------------------------------------------------------------
  564.  
  565. From ts@uwasa.fi Fri Nov 8 00:00:40 1996
  566. Subject: Executable branding
  567.  
  568. 40. *****
  569.  Q: How can I write (brand) something into my executables?
  570.     Here is the actual question that led me to writing this item: 'I
  571.     am very interested in the .EXE "branding" techniques you use in
  572.     your TSUNTI unit. Would it be possible to get hold of the source
  573.     code for that unit, as it would save me from having to re-invent
  574.     the wheel?'
  575.  
  576.  A: What you are referring to is
  577.  BRANDEXE Store information within your program's .exe file (MS-DOS 3.0+)
  578.  CHKSUMFN Checksum self-test to detect any tampering (MS-DOS 3.0+)
  579.  USECOUNT Get the number of times the program has been used
  580. Sorry no, I don't want to distribute my source codes from
  581. ftp://garbo.uwasa.fi/pc/turbopas/ts/tspa3570.zip. Besides they would
  582. be less useful to you than you may think because internally my
  583. programs are in Finnish, comments, variable and procedure names, and
  584. all. But I can hopefully help you by giving a reference to a similar
  585. code.  Please see Ohlsen & Stoker, Turbo Pascal Advanced Techniques,
  586. Que, 1989, p. 420.
  587. --------------------------------------------------------------------
  588.  
  589. From ts@uwasa.fi Fri Nov 8 00:00:41 1996
  590. Subject: Elusive, inconsistent errors
  591.  
  592. 41. *****
  593.  Q: What is wrong with my program? It hangs without a clear pattern?
  594.  
  595.  A: With experience one learns that some programming errors are very
  596. elusive. I have many times seen users declaring that they have found
  597. a bug in Turbo Pascal, but in the overwhelming majority of cases it
  598. still is just a programming error, which just is more difficult to
  599. find than the more clear-cut cases. When you have symptoms like your
  600. program crashing from within the IDE, but working seemingly all
  601. right when called as stand-alone, or something equally strange, you
  602. might have one of the following problems.
  603. - A variable or some variables in your code are uninitialized thus
  604.   getting random values, which differ depending on your environment.
  605. - Your indexes are overflowing. Set on the range check {$R+}
  606.   directive for testing.
  607. - An error in the pointer logic.
  608. Normal debugging does not necessarily help in locating these errors
  609. because one is easily led to debugging the wrong parts of one's
  610. program. Especially the latter two reasons can cause errors which
  611. seemingly have nothing to do with the actual cause. This results
  612. from the fact that indexing and pointer errors can overwrite parts
  613. of memory causing strange quirks in your program. If you have used
  614. indexing with {$R-} or if you use pointer operations, sooner or
  615. later you are bound to have these problems in developing your
  616. applications.
  617.    See Edward Mitchell (1993), Borland Pascal Developer's Guide,
  618. 275-288 for common programming errors and especially the information
  619. on memory clobbering, in a useful chapter on debugging Turbo Pascal
  620. programs. You might also take a look at your Turbo Pascal User's
  621. Guide. At least version 7.0 has an instructive general
  622. categorization of errors on pages 76-77.
  623. --------------------------------------------------------------------
  624.  
  625. From ts@uwasa.fi Fri Nov 8 00:00:42 1996
  626. Subject: Converting the number base
  627.  
  628. 42. *****
  629.  Q: How do I convert a decimal word into a hexadecimal string, etc?
  630.  
  631.  A: Here is one possibility
  632.   function HEXFN (decimal : word) : string;
  633.   const hexDigit : array [0..15] of char = '0123456789ABCDEF';
  634.   begin
  635.     hexfn := hexDigit[(decimal shr 12)]
  636.           + hexDigit[(decimal shr 8) and $0F]
  637.           + hexDigit[(decimal shr 4) and $0F]
  638.           + hexDigit[(decimal and $0F)];
  639.   end;  (* hexfn *)
  640. Here is another conversion example (from longint to binary string)
  641.   function LBINFN (decimal : longint) : string;
  642.   const BinDigit : array [0..1] of char = '01';
  643.   var i     : byte;
  644.       binar : string;
  645.   begin
  646.     FillChar (binar, SizeOf(binar), ' ');
  647.     binar[0] := chr(32);
  648.     for i := 0 to 31 do
  649.       binar[32-i] := BinDigit[(decimal shr i) and 1];
  650.     lbinfn := binar;
  651.   end;  (* lbinfn *)
  652. For a full set of conversions, both from and to decimal, apply
  653. TSUTNTB.TPU from ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip.
  654. --------------------------------------------------------------------
  655.  
  656. From ts@uwasa.fi Fri Nov 8 00:00:43 1996
  657. Subject: Identifying the last drive
  658.  
  659. 43. *****
  660.  Q: How to determine the last drive?
  661.  
  662.  A: One way of doing that is utilizing the information in DPB, that
  663. is the Drive Parameter Block, but that is rather complicated, so you
  664. can find that without source code in the TSUNTH unit in
  665. ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip .
  666.  Another way is using interrupt 21H, function 36H to detect if a
  667. drive exists starting from the first drive letter. The code is given
  668. below. The disadvantage of this method is that it does not
  669. distinguish between real and substituted drives.
  670.   uses Dos;
  671.   function LASTDFN : char;  (* Detect last harddisk letter *)
  672.   var regs : registers;
  673.       i    : byte;
  674.   begin
  675.     i := 2;
  676.     repeat
  677.       Inc(i);
  678.       FillChar (regs, SizeOf(regs), 0);
  679.       regs.ah := $36;
  680.       regs.dl := i;
  681.       MsDos(regs);
  682.     until (regs.ax = $FFFF);
  683.     lastdfn := chr(i+63);
  684.   end;  (* lastdfn *)
  685. --------------------------------------------------------------------
  686.  
  687. From ts@uwasa.fi Fri Nov 8 00:00:44 1996
  688. Subject: Clock display in a TP program
  689.  
  690. 44. *****
  691.  Q: How can I put a running clock into my Turbo Pascal program?
  692.  
  693.  A: We are not speaking of a stand-alone TSR-clock (which is a
  694. different task), but considering a clock that continuously displays
  695. the time in some part of the output screen of your Turbo Pascal
  696. program.
  697.     You might first want to read the earlier items about ReadKey
  698. usages if you are not familiar with it (you probably are, because
  699. you would not pose this advanced question if you were a novice). The
  700. items are the unlikely "How do I disable or capture the break key in
  701. Turbo Pascal?" and "How can I read input without echoing to the
  702. screen?"
  703.    The general idea is to make the body of the program a repeat
  704. until loop using ReadKey for input and updating the clock display
  705. at suitable junctions within the loop. The scheme is thus something
  706. like the following.
  707.   procedure showtime;
  708.     begin
  709.       { if the second has changed, write the time }
  710.     end;
  711.   :
  712.   repeat
  713.     { do whatever }
  714.     showtime;
  715.     if KeyPressed then
  716.       case ReadKey of
  717.         { whatever }
  718.         { exit rules }
  719.       end;
  720.     showtime;
  721.     :
  722.     showtime;
  723.   until false;
  724.    One trick of the trade is that you must not update your clock
  725. each time the clock routine is encountered. You should test if the
  726. second has changed, and update only then. Else you are liable to get
  727. an annoying flicker in your clock.
  728. --------------------------------------------------------------------
  729.  
  730. From ts@uwasa.fi Fri Nov 8 00:00:45 1996
  731. Subject: Is a name a directory
  732.  
  733. 45. *****
  734.  Q: How to establish if a name refers to a directory or not?
  735.  
  736.  A: This question has turned out a bit more complicated than I first
  737. thought. There are several methods, each with some catch. The first
  738. is trying to open the name as a file and observing the IOResult. The
  739. ISDIRFN function in ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip TPU unit
  740. TSUNTJ.TPU is based on this method. Unfortunately it is not always
  741. stable. I have been reported problems in connection with DRDOS by
  742. Richard Breuer (ricki@pool.informatik.rwth-aachen.de) who has
  743. tested these routines.
  744.   The second method (ISDIR2FN) is based on the fact that the file
  745. NUL exists in a directory if the directory exists.
  746.   The thrid method (ISDIR3FN) is a brute force method. It is given
  747. below, since it is quite an instructive little exercise of Turbo
  748. Pascal programming.
  749.   (* Search recursively through a drive's directories.
  750.      Auxiliary, recursive procedure for ISDIR3FN *)
  751.   procedure SEARCHDR (Path, FileSpec : string;
  752.                       name           : string;
  753.                       var found      : boolean);
  754.   var FileInfo : SearchRec;
  755.   begin
  756.     FindFirst (Path + '*.*', Directory, FileInfo);
  757.     while DosError = 0 do
  758.       begin
  759.         if ((FileInfo.Attr and Directory) > 0) and
  760.             (FileInfo.Name <> '.') and
  761.             (FileInfo.Name <> '..') then
  762.               begin
  763.                 SEARCHDR (Path + FileInfo.Name + '\',
  764.                           FileSpec,
  765.                           name,
  766.                           found);
  767.                 if Path + FileInfo.Name + '\' = name then
  768.                   found := true;
  769.               end;
  770.         FindNext (FileInfo);
  771.       end; {while}
  772.   end;  (* searchdr *)
  773.  
  774.   (* Does a name refer to a directory *)
  775.   function ISDIR3FN (name : string) : boolean;
  776.   var drive : char;
  777.       found : boolean;
  778.   begin
  779.     {... Default value ...}
  780.     isdir3fn := false;
  781.     {... Discard empty names ...}
  782.     if name = '' then exit;
  783.     {... Expand into a fully qualified name, makes it uppercase ...}
  784.     name := FExpand (name);
  785.     if name[Length(name)] <> '\' then name := name + '\';
  786.     {... Extract the drive letter from the name ...}
  787.     drive := UpCase (name[1]);
  788.     {... Check first for the root ...}
  789.     if drive + ':\' = name then
  790.       begin isdir3fn := true; exit; end;
  791.     {... Check the rest of the directories recursively ...}
  792.     found := false;
  793.     SEARCHDR (drive + ':\', '*.*', name, found);
  794.     isdir3fn := found;
  795.   end;  (* isdir3fn *)
  796.  
  797. -Date: Mon, 13 Jun 1994 00:13:05 +0000 (GMT)
  798. -From: JEROEN SCHIPPER <JSCHIPPER@HUT.NL>
  799. -To: ts@uwasa.fi (Timo Salmi)
  800. -Subject: Is a name a directory in TP
  801.  
  802. The method I use is simply checking the attribute bit, as this small
  803. program will demonstrate:
  804.   program isdir;
  805.   uses dos;
  806.   var s:string;
  807.       attr:word;
  808.       f:file;
  809.   begin
  810.     repeat
  811.       readln(s);
  812.       if s = '' then break;
  813.       assign(f,s);
  814.       getfattr(f,attr);
  815.       if doserror <> 0 then
  816.         writeln('DOS error code = ', doserror)
  817.       else
  818.       begin
  819.         if attr and directory <> 0 then
  820.           writeln(S,' is a directory')
  821.         else
  822.           writeln(S,' is a not directory')
  823.       end;
  824.     until false;
  825.   end.
  826. The methods you mention in your faq are far more complicated, but
  827. why? Is there are catch why the method above won't work? I guess
  828. don't really understand the problem here.
  829. Jeroen.
  830.    Timo's answer. That is a good point. Jeroen's solution translates
  831. into the following function:
  832.   Uses Dos;
  833.   (* Is the given path a directory *)
  834.   function DEXISTFN (path : string) : boolean;
  835.   var f    : file;
  836.       attr : word;
  837.   begin
  838.     dexistfn := false;
  839.     Assign (f, path);
  840.     GetFAttr (f, attr);
  841.     if DosError = 0 then
  842.       if (attr and Directory) <> 0 then
  843.         dexistfn := true;
  844.   end;  (* dexistfn *)
  845. Note the syntax of the directory paths. For a root directory it is
  846. e.g. C:\ with the trailing backslash while for a subdirectory it is
  847. C:\DOS without a trailing backslash.
  848.  
  849.  A2: This has turned out to be a tricky FAQ. There are some
  850. additional suggestions and comments from the gentle readers. You can
  851. track them from ftp://garbo.uwasa.fi/pc/ts/tspost00.zip index.
  852. --------------------------------------------------------------------
  853.  
  854. From ts@uwasa.fi Fri Nov 8 00:00:46 1996
  855. Subject: Disabling alt-ctrl-del
  856.  
  857. 46. *****
  858.  Q: How does one disable alt-ctrl-del?
  859.  
  860.  A: I can only give a pointer to source code. Take a look at
  861.  4067 Jul 1 1993 ftp://garbo.uwasa.fi/pc/turbopa7/cadthf10.zip
  862.  cadthf10.zip CadThief TP6+ unit for trapping ctrl+alt+del, M.Hanninen
  863. and
  864.  30673 Oct 13 1987 ftp://garbo.uwasa.fi/pc/turbopas/keyint.zip
  865.  keyint.zip Disable alt-ctrl-del + other int09h TP tricks, N.Rubenking
  866. and
  867.  7105 Apr 19 1995 ftp://garbo.uwasa.fi/pc/turbopa7/cad_int9.zip
  868.  cad_int9.zip Disable Ctrl-Alt-Del via new TP kb interrupt, J.Robertson
  869. Also see Lou Duchez's source code in TSR.SWG examples in the fine
  870. SWAG (SourceWare Archival Group's) collection of TP sources.
  871. Available from the /pc/turbopas directory at Garbo. For the current
  872. references to the SWAG files see ftp://garbo.uwasa.fi/pc/INDEX.ZIP.
  873.    I have utilized alt-ctrl-del disabling at least in one of my own
  874. programs (PESTIKID.EXE). The code is not available, but the general
  875. idea is replacing the old keyboard interrupt ($09) with a handler of
  876. one's own. If the handler detects alt-ctrl-del, the keyboard is
  877. reset, else the handler is chained back to the original interrupt.
  878. The chaining requires a rather complicated inline procedure provided
  879. in TurboPower Software's kit. An additional complication is that the
  880. del keypress must be intercepted already at the relevant port $60,
  881. and the alt and ctrl status must be tested, so that the rebooting
  882. will not be invoked. Resetting the keyboard requires accessing the
  883. $20 and $61 ports.
  884. --------------------------------------------------------------------
  885.  
  886. From ts@uwasa.fi Fri Nov 8 00:00:47 1996
  887. Subject: Does a file exist
  888.  
  889. 47. *****
  890.  Q: How can I test whether a file exists?
  891.  
  892.  A: There are several alternatives. Here is the most common with
  893. example code. It recognizes also read-only, hidden and system files.
  894.   function FILEXIST (name : string) : boolean;
  895.   var fm : byte;
  896.       f  : file;
  897.       b  : boolean;
  898.   begin
  899.     fm := FileMode;
  900.     FileMode := 0;
  901.     assign (f, name);
  902.     {$I-} reset(f); {$I+}
  903.     b := IOResult = 0;
  904.     if b then close(f);
  905.     filexist := b;
  906.     FileMode := fm;
  907.   end;
  908. A comment from Chris Rankin: "FileMode := $40 is better; This is the
  909. same as (fmOpenRead or fmShareDenyNone) and so will not fail in a
  910. networked environment when someone else has opened the file."
  911.  
  912. A second alternative is
  913.   Uses Dos;
  914.   function FILEXIST (name : string) : boolean;
  915.   var f  : file;
  916.       a  : word;
  917.   begin
  918.     assign (f, name);
  919.     GetFAttr (f, a);
  920.     filexist := false;
  921.     if DosError = 0 then
  922.       if ((a and Directory) = 0) and ((a and VolumeId) = 0) then
  923.         filexist := true;
  924.   end;
  925.  
  926. A third alternative is
  927.   Uses Dos;
  928.   function FILEXIST (name : PathStr) : boolean;
  929.   begin
  930.     filexist := FSearch (name, '') <> '';
  931.   end;
  932.  
  933. A fourth alternative is the following. Be careful with this option,
  934. since it works a bit differently from the others. It accepts wild
  935. cards. Thus, for example FILEXIST('c:\autoexec.*') would be TRUE in
  936. this method, while FALSE in all the above.
  937.   Uses Dos;
  938.   function FILEXIST (name : string) : boolean;
  939.   var f : SearchRec;
  940.   begin
  941.     filexist := false;
  942.     FindFirst (name, AnyFile, f);
  943.     if DosError = 0 then
  944.       if (f.attr <> Directory) and (f.attr <> VolumeId) then
  945.         filexist := true;
  946.   end;
  947. A good variation from KDT@newton.national-physical-lab.co.uk of this
  948. theme, disallowing wildcards:
  949.   function file_exists (fname :string) :boolean;
  950.   var f :searchrec;
  951.   begin
  952.     findfirst (fname, anyfile - directory - volumeid, f);
  953.     file_exists := (doserror + pos('*',fname) + pos('?',fname) = 0);
  954.   end;
  955. --------------------------------------------------------------------
  956.  
  957. From ts@uwasa.fi Fri Nov 8 00:00:48 1996
  958. Subject: The current program name
  959.  
  960. 48. *****
  961.  Q: What is the name of the current Turbo Pascal program?
  962.  
  963.  A: The name of the currently executing Turbo Pascal program is in
  964. ParamStr(0).
  965.    This was introduced in TP version 5.0, and as far as I recall at
  966. least MS-DOS version 3.0 is required. For TP 4.0 you can use
  967. "ParamStr0 The name of the program" from TSUNT45 in
  968. ftp://garbo.uwasa.fi/pc/ts/tspa3540.zip (or whatever the version
  969. number is the latest).
  970.    It is advisable to put the value into a string variable at be
  971. beginning of the program before eny I/O takes place. Thus you might
  972. wish to use:
  973.   var progname : string;
  974.   begin  { the main program }
  975.     progname := ParamStr(0);
  976.     :
  977. A bonus of this method is that you can access the individual
  978. characters of progname (e.g. progname[1] for the drive) while that
  979. is not possible to do for the ParamStr keyword.
  980. --------------------------------------------------------------------
  981.  
  982. From ts@uwasa.fi Fri Nov 8 00:00:49 1996
  983. Subject: How can a program reboot my PC?
  984.  
  985. 49. *****
  986.  Q: How is the code for rebooting the PC written in Turbo Pascal?
  987.  
  988.  A: This item draws from the information and the C-code example in
  989. Stan Brown's, later J.Carlyle's comp.os.msdos.programmer FAQ,
  990. ftp://garbo.uwasa.fi/pc/doc-net/dosfv206.zip (at the time of
  991. updating this), from memory.lst and interrup.b in
  992. ftp://garbo.uwasa.fi/pc/programming/inter52b.zip, and from
  993. ftp://garbo.uwasa.fi/pc/programming/helppc21.zip. The Turbo Pascal
  994. code is my adaptation of the C-code. It is not a one-to-one port.
  995.    The usually advocated warm-boot method is storing $1234 in the
  996. word at $0040:$0072 and jumping to address $FFFF:$0000. The problem
  997. with this approach is that files must first be closed, potential
  998. caches flushed. This is how to do this
  999.   procedure REBOOT;
  1000.   label next;
  1001.   var regs  : registers;
  1002.       i     : byte;
  1003.       ticks : longint;
  1004.   begin
  1005.     {... "press" alt-ctrl ...}
  1006.     mem[$0040:$0017] := mem[$0040:$0017] or $0C;  { 00001100 }
  1007.     {... "press" del, try a few times ...}
  1008.     for i := 1 to 10 do
  1009.       begin
  1010.         FillChar (regs, sizeOf(regs), 0);  { initialize }
  1011.         regs.ah := $4F;  { service number }
  1012.         regs.al := $53;  { del key's scan code }
  1013.         regs.flags := FCarry;  { "sentinel for ignoring key" }
  1014.         Intr ($15, regs);
  1015.         {... check if the del key registered, if not retry ...}
  1016.         if regs.flags and Fcarry > 0 then goto next;
  1017.         {... waste some time, watch out for midnight ...}
  1018.         ticks := MemL [$0040:$006C];
  1019.         repeat until (MemL[$0040:$006C] - ticks > 3) or
  1020.                      (MemL[$0040:$006C] - ticks < 0)
  1021.     end; {for}
  1022.     exit;
  1023.   next:
  1024.     {... disk reset: writes all modified disk buffers to disk ...}
  1025.     FillChar (regs, sizeOf(regs), 0);
  1026.     regs.ah := $0D;
  1027.     MsDos (regs);
  1028.     {... set post-reset flag, use $0000 instead of $1234 for coldboot ...}
  1029.     memW[$0040:$0072] := $1234;
  1030.     {... jump to $FFFF:0000 BIOS reset ...}
  1031.     Inline($EA/$00/$00/$FF/$FF);
  1032.   end;  (* reboot *)
  1033. One slight problem with this approach is that the keyboard intercept
  1034. interrupt $15 service $4F requires at least an AT according to
  1035. ftp://garbo.uwasa.fi/pc/programming/inter52b.zip. A simple test
  1036. based on "FFFF:E byte ROM machine id" (the previous definition is
  1037. from ftp://garbo.uwasa.fi/pc/programming/helppc21.zip) is:
  1038.   function ISATFN : boolean;
  1039.   begin
  1040.      case Mem[$F000:$FFFE] of
  1041.        $FC, $FA, $F8 : isatfn := true;
  1042.        else isatfn := false;
  1043.      end; {case}
  1044.   end;  (* isatfn *)
  1045. For a more comprehensive test use CPUFN "Get the type of the
  1046. processor chip" from TSUNTH in ftp://garbo.uwasa.fi/pc/ts/tspa3570.zip
  1047. or see the TP + ASM code in Michael Ticher (1992), PC Intern System
  1048. Programming, pp. 725-727.
  1049.  
  1050.    An addition by Per Bergland (d6caps@dtek.chalmers.se): I recently
  1051. downloaded the FAQ for this newsgroup, and studied the code for
  1052. rebooting a PC. The problem with that code (calling FFFF:0000) is
  1053. that it will not work in protected mode programs such as those
  1054. compiled for Windows or BP7 DPMI, or even in a DOS program run in a
  1055. Windows DOS session. The solution provided has been tested on
  1056. various COMPAQ PC:s, but I think it will work on any AT-class
  1057. machine. It involves using the 8042 keyboard controller chip output
  1058. pin 0, which is physically connected to the reset pin of the CPU.
  1059. There is unfortunately no way to perform a "warm" reboot this way,
  1060. and the warnings about disk caches etc apply to this code, too (see
  1061. FAQ). The code is written in BP7 assembly lingo, because that's what
  1062. I normally write code in, but anyone could rewrite it in C or high
  1063. level Pascal.
  1064.   UNIT Reboot;
  1065.   INTERFACE
  1066.     procedure DoReboot;
  1067.   IMPLEMENTATION
  1068.     procedure DoReboot;assembler;
  1069.     asm
  1070.       cli
  1071.   @@WaitOutReady:       { Busy-wait until 8042 is ready for new command}
  1072.       in al,64h         { read 8042 status byte}
  1073.       test al,00000010b { Bit 1 of status indicates input buffer full }
  1074.       jnz @@WaitOutReady
  1075.       mov al,0FEh       { Pulse "reset" = 8042 pin 0 }
  1076.       out 64h,al
  1077.       { The PC will reboot now }
  1078.     end;
  1079.   END.
  1080. --------------------------------------------------------------------
  1081.  
  1082. From ts@uwasa.fi Fri Nov 8 00:00:50 1996
  1083. Subject: Writing inline code
  1084.  
  1085. 50. *****
  1086.  Q: How can I write inline code?
  1087.  
  1088.  A: In Turbo Pascal versions prior 6.0 assembler code could not be
  1089. directly included in the code. Instead one had to assemble the code
  1090. into inline statements. Consider the task of rebooting the PC
  1091. (without disk closing and cache flushing).  The assembler code for
  1092. this is
  1093.   mov ax,$40
  1094.   mov ds,ax
  1095.   mov wo [$72],$1234
  1096.   jmp $FFFF:$0000
  1097. To assemble this code into an inline statement write the following
  1098. file calling it e.g. debug.in.  The empty line is important. Also
  1099. carefully note that debug assumes hexadecimal notation. Do not use
  1100. the $ designator in debug.in.
  1101.   .... begin debug.in, cut here ....
  1102.   a 100
  1103.   mov ax,40
  1104.   mov ds,ax
  1105.   mov wo [72],1234
  1106.   jmp FFFF:0000
  1107.  
  1108.   u 100
  1109.   q
  1110.   .... end debug.in, cut here ....
  1111. Give the following command
  1112.   debug < debug.in
  1113. You'll get
  1114.   0E9E:0100 B84000        MOV     AX,0040
  1115.   0E9E:0103 8ED8          MOV     DS,AX
  1116.   0E9E:0105 C70672003412  MOV     WORD PTR [0072],1234
  1117.   0E9E:010B EA0000FFFF    JMP     FFFF:0000
  1118. This translates into
  1119.     Inline ($B8/$40/$00/
  1120.             $8E/$D8/
  1121.             $C7/$06/$72/$00/$34/$12/
  1122.             $EA/$00/$00/$FF/$FF);
  1123.  
  1124.  A2: You can also utilize an inline <--> asm converter called
  1125.   ftp://garbo.uwasa.fi/pub/pc/turbopas/inlin219.zip
  1126.   inlin219.zip Inline assembler for Turbo Pascal, w/src, D.Baldwin
  1127. It has two sources, inline.pas and uninline.pas which you can
  1128. compile to do the conversions in both directions for you. For
  1129. example, if you have a file test.asm containing the
  1130.   mov ax,$0040
  1131.   mov ds,ax
  1132.   mov word ptr [$72],$1234
  1133.   jmp far $FFFF:$0000
  1134. then "inline test.asm" will produce test.obj with the following,
  1135. expected contents
  1136.   Inline(
  1137.     $B8/$40/$00/           {mov ax,$0040}
  1138.     $8E/$D8/               {mov ds,ax}
  1139.     $C7/$06/$72/$00/$34/$12/ {mov word ptr [$72],$1234}
  1140.     $EA/$00/$00/$FF/$FF);  {jmp far $FFFF:$0000}
  1141. --------------------------------------------------------------------
  1142.  
  1143.